package cz.cvut.fit.gephi.multimode;

import java.util.HashSet;
import java.util.Set;

import org.gephi.graph.api.Column;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.GraphController;
import org.gephi.graph.api.Node;
import org.gephi.graph.api.Table;
import org.gephi.project.api.ProjectController;
import org.gephi.project.api.Workspace;
import org.gephi.project.api.WorkspaceListener;
import org.gephi.utils.longtask.api.LongTaskExecutor;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//cz.cvut.fit.gephi.multimode//MultiModeWindow//EN",
        autostore = false)
@TopComponent.Description(preferredID = "MultiModeWindowTopComponent",
        iconBase = "cz/cvut/fit/gephi/multimode/resources/lightning.png",
        persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "filtersmode", openAtStartup = true)
@ActionID(category = "Window", id = "cz.cvut.fit.gephi.multimode.MultiModeWindowTopComponent")
@ActionReference(path = "Menu/Window" /*
 * , position = 333
 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_MultiModeWindowAction",
        preferredID = "MultiModeWindowTopComponent")
@Messages({
    "CTL_MultiModeWindowAction=MultiMode Projections",
    "CTL_MultiModeWindowTopComponent=MultiMode Networks Projection",
    "HINT_MultiModeWindowTopComponent=Enables projection of multimode networks"
})
/**
 * @author Jaroslav Kuchar
 */
public final class MultiModeWindowTopComponent extends TopComponent {
    private final ProjectController projectController;
    public MultiModeWindowTopComponent() {
        initComponents();
        setName(Bundle.CTL_MultiModeWindowTopComponent());
        setToolTipText(Bundle.HINT_MultiModeWindowTopComponent());
        
        // Make sure project and workspace exists
        projectController = Lookup.getDefault().lookup(ProjectController.class);
        checkPluginEnabling();
        projectController.addWorkspaceListener(new WorkspaceListener(){
            public void initialize(Workspace wrkspc) {
                load.setEnabled(true);
            }

            public void select(Workspace wrkspc) {
                checkPluginEnabling();
            }

            public void unselect(Workspace wrkspc) {
                checkPluginEnabling();
            }

            public void close(Workspace wrkspc) {
                checkPluginEnabling();
            }

            public void disable() {
                checkPluginEnabling();
            }
        });
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        attributes = new javax.swing.JComboBox();
        firstMatrix = new javax.swing.JComboBox();
        secondMatrix = new javax.swing.JComboBox();
        removeEdges = new javax.swing.JCheckBox();
        removeNodes = new javax.swing.JCheckBox();
        attributeLabel = new javax.swing.JLabel();
        leftlabel = new javax.swing.JLabel();
        rightLabel = new javax.swing.JLabel();
        start = new javax.swing.JButton();
        load = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        graphColoring = new javax.swing.JButton();
        bipartiteLabel = new javax.swing.JLabel();

        attributes.setToolTipText(org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.attributes.toolTipText")); // NOI18N
        attributes.setEnabled(false);
        attributes.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                attributesActionPerformed(evt);
            }
        });

        firstMatrix.setToolTipText(org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.firstMatrix.toolTipText")); // NOI18N
        firstMatrix.setEnabled(false);
        firstMatrix.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                firstMatrixActionPerformed(evt);
            }
        });

        secondMatrix.setToolTipText(org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.secondMatrix.toolTipText")); // NOI18N
        secondMatrix.setEnabled(false);

        org.openide.awt.Mnemonics.setLocalizedText(removeEdges, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.removeEdges.text")); // NOI18N
        removeEdges.setToolTipText(org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.removeEdges.toolTipText")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(removeNodes, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.removeNodes.text")); // NOI18N
        removeNodes.setToolTipText(org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.removeNodes.toolTipText")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(attributeLabel, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.attributeLabel.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(leftlabel, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.leftlabel.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(rightLabel, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.rightLabel.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(start, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.start.text")); // NOI18N
        start.setEnabled(false);
        start.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(load, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.load.text")); // NOI18N
        load.setEnabled(false);
        load.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(graphColoring, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.graphColoring.text")); // NOI18N
        graphColoring.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                graphColoringActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(bipartiteLabel, org.openide.util.NbBundle.getMessage(MultiModeWindowTopComponent.class, "MultiModeWindowTopComponent.bipartiteLabel.text")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(removeNodes)
                            .addComponent(removeEdges))
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(attributeLabel)
                                    .addComponent(leftlabel)
                                    .addComponent(rightLabel))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(secondMatrix, 0, 191, Short.MAX_VALUE)
                                    .addComponent(firstMatrix, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(attributes, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addGap(0, 0, Short.MAX_VALUE)
                                .addComponent(start))
                            .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING))
                        .addContainerGap())))
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(load)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(graphColoring)
                        .addGap(32, 32, 32)
                        .addComponent(bipartiteLabel)))
                .addGap(0, 0, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(load)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(attributes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(attributeLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(firstMatrix, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(leftlabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(secondMatrix, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(rightLabel))
                .addGap(18, 18, 18)
                .addComponent(removeEdges)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(removeNodes)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(start)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(graphColoring)
                    .addComponent(bipartiteLabel))
                .addContainerGap(60, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void attributesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_attributesActionPerformed

        firstMatrix.removeAllItems();
        secondMatrix.removeAllItems();
        start.setEnabled(false);
        if (attributes.getSelectedIndex() > 0) {
            Column col = (Column) attributes.getSelectedItem();

            // load all possible values of attribute
            GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
            Graph graph = graphController.getGraphModel().getGraphVisible();
            Node[] nodes = graph.getNodes().toArray();
            Set<String> vals = new HashSet<String>();
            for (Node n : nodes) {
                Object val = n.getAttribute(col);
                if (val != null) {
                    vals.add(val.toString());
                } else {
                    vals.add("null");
                }
            }
            // add combinations
            for (String left : vals) {
                for (String right : vals) {
                    firstMatrix.addItem(new ValueCombination(left, right));
                }
            }
            if (firstMatrix.getItemCount() > 0) {
                firstMatrix.setSelectedIndex(0);
            }
        }
    }//GEN-LAST:event_attributesActionPerformed

    private void firstMatrixActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_firstMatrixActionPerformed
        // TODO reaction on selected first matrix                
        secondMatrix.removeAllItems();
        if (attributes.getSelectedIndex() > 0) {

            Column col = (Column) attributes.getSelectedItem();

            // load all possible values of attribute
            GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
            Graph graph = graphController.getGraphModel().getGraphVisible();
            Node[] nodes = graph.getNodes().toArray();
            Set<String> vals = new HashSet<String>();
            for (Node n : nodes) {
                Object val = n.getAttribute(col);
                if (val != null) {
                    vals.add(val.toString());
                } else {
                    vals.add("null");
                }
            }
            // add combination with right dimension on left side
            for (String left : vals) {
                if (firstMatrix.getSelectedItem() != null && left.equals(((ValueCombination) firstMatrix.getSelectedItem()).getSecond())) {

                    for (String right : vals) {
                        secondMatrix.addItem(new ValueCombination(left, right));
                    }
                }
            }
            if (secondMatrix.getItemCount() > 0) {
                secondMatrix.setSelectedIndex(0);
            }

            start.setEnabled(true);
        }
    }//GEN-LAST:event_firstMatrixActionPerformed

    private void startActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startActionPerformed
        LongTaskExecutor executor = new LongTaskExecutor(true);
        LongTaskTransformation longTask = new LongTaskTransformation((Column) attributes.getSelectedItem(), ((ValueCombination) firstMatrix.getSelectedItem()).getFirst(), ((ValueCombination) firstMatrix.getSelectedItem()).getSecond(), ((ValueCombination) secondMatrix.getSelectedItem()).getSecond(), removeEdges.isSelected(), removeNodes.isSelected());
        executor.execute(longTask, longTask, "Transformation...", null);

        if (attributes.getItemCount() > 0 && (removeEdges.isSelected() || removeNodes.isSelected())) {
            firstMatrix.removeAllItems();
            secondMatrix.removeAllItems();
            attributes.setSelectedIndex(attributes.getSelectedIndex());
        }
    }//GEN-LAST:event_startActionPerformed

    private void loadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadActionPerformed
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
        Table nodeTable = graphController.getGraphModel().getNodeTable();

        attributes.removeAllItems();
        attributes.addItem("...");

        for (Column ac : nodeTable.toList()) {
            if (!ac.getTitle().equals("Id") && !ac.getTitle().equals("Label")) {
                attributes.addItem(ac);
            }
        }
        attributes.setEnabled(true);
        firstMatrix.setEnabled(true);
        secondMatrix.setEnabled(true);
    }//GEN-LAST:event_loadActionPerformed

    private void graphColoringActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_graphColoringActionPerformed
        // TODO add your handling code here:
        GraphColoring gc = new GraphColoring();
        boolean bipartite = gc.bipartite();
        bipartiteLabel.setText("Bipartite: " + bipartite);
    }//GEN-LAST:event_graphColoringActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel attributeLabel;
    private javax.swing.JComboBox attributes;
    private javax.swing.JLabel bipartiteLabel;
    private javax.swing.JComboBox firstMatrix;
    private javax.swing.JButton graphColoring;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JLabel leftlabel;
    private javax.swing.JButton load;
    private javax.swing.JCheckBox removeEdges;
    private javax.swing.JCheckBox removeNodes;
    private javax.swing.JLabel rightLabel;
    private javax.swing.JComboBox secondMatrix;
    private javax.swing.JButton start;
    // End of variables declaration//GEN-END:variables

    @Override
    public void componentOpened() {
        // TODO add custom code on component opening
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }
    
    private boolean isProjectWorkspaceOk(){
        return projectController.getCurrentProject()!= null && 
               projectController.getCurrentWorkspace() != null;
    }
    private void checkPluginEnabling(){
        if(isProjectWorkspaceOk()) {
            load.setEnabled(true);
            graphColoring.setEnabled(true);
        } else {
            load.setEnabled(false);
            graphColoring.setEnabled(false);
        }
    }
}
